Skip to content

host: keep a Session added while remove-agent awaits its archives - #2617

Merged
Birfy merged 1 commit into
mainfrom
dev/2616-remove-agent-live-sessions
Nov 7, 2026
Merged

Birfy merged 1 commit into
mainfrom
dev/2616-remove-agent-live-sessions

Conversation

@Birfy

@Birfy Birfy commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Written-by: Dev
Owner: Dev
Reviewer: Reviewer

Fixes #2616

remove-agent copied the DSH Agent's Session list, awaited one archiveSession per Session and
then wrote that pre-await copy back (record(agentId).sessions = kept), so a Session another
request added while it waited was dropped; when every archive succeeded the record was deleted
outright and the new Session was orphaned. The removal now applies its own outcome to the live
record: the kept branch filters out exactly the ids it archived (in rt.mutate), and the
all-archived branch keeps the Sessions the snapshot did not have and answers a retryable error
instead of deleting the record, so nothing is lost and a retry archives that Session.
archiveAgentSession, createAgentSession, adoptAgentSession and addAgent's rollback are
untouched; no compare-and-swap, no new endpoint, no UI change.

Ran at this tip: 645a9e9

$ cd core && DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness TZ=UTC node --import ./test/harness-resolve.mjs --test test/agents.test.js
ok 9 - remove-agent drops only the Sessions it archived and keeps one added while it waited
ok 10 - remove-agent keeps the Agent and answers the retry error when a Session joins during the removal
# tests 16
# pass 16
# fail 0
exit 0

$ node scripts/ds-bot-patches.mjs check
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

$ node .github/scripts/changelog.mjs check
changelog: 18 fragment(s) in changelog.d/ are well formed

$ cd core && npx oxlint src test
Found 81 warnings and 0 errors.   (warnings pre-existing; lint tolerates them)

$ node core/scripts/build-client.mjs --check
exit 0

$ node .github/scripts/check-mojibake.mjs --check
mojibake: ok — 0 occurrences of U+FFFD in 1542 text file(s)

Not run: npm run verify (full suite; scoped to the target test), ds-bot-patches.mjs canonical
and arch-docs (both need git, absent on the dev box; core/ and patches/ were kept
byte-identical by check), smoke bench.

Red first: on the unmodified implementation the two new tests fail — ["s2"] instead of
["s2","s3"], and ok:true with the record deleted instead of the retryable error.

Checkpoint

{
"pr": 2617,
"claim": "Dev",
"issue": 2616,
"summary": "remove-agent no longer writes back the Session list it read before awaiting one archive per Session. The kept branch now filters the ids it actually archived out of the live record, and the all-archived branch keeps any Session added meanwhile and answers a retryable error instead of deleting the record, so a Session added during the removal is never dropped or orphaned. Two tests gate the archive hook and reproduce both interleavings; both were red before the fix.",
"files": [
"core/src/host/agents.js",
"core/test/agents.test.js",
"changelog.d/2616.fixed.md",
"docs/subsystems/core-host.md",
"patches/ds-bot/0001-core-fixes.patch"
],
"checks": { "ran": "node --import ./test/harness-resolve.mjs --test test/agents.test.js; node scripts/ds-bot-patches.mjs check; node .github/scripts/changelog.mjs check; npx oxlint src test; node core/scripts/build-client.mjs --check; node .github/scripts/check-mojibake.mjs --check", "result": "green", "at": "645a9e95cec3a136b4db4f24a280bcb7c0f6c43d" },
"next": "Reviewer: judge the tip for T2/T3. Nothing else pending."
}

remove-agent wrote back the Session list it read before awaiting one archive per
Session, so a Session added meanwhile was dropped; when every archive succeeded it
deleted the record and orphaned that Session. The removal now applies its own
archives to the live record and keeps a late Session, asking for a retry instead.

Refs #2616
@Birfy Birfy added the agent-pr Pull request opened by an agent label Nov 7, 2026
@Birfy Birfy self-assigned this Nov 7, 2026
@Birfy

Birfy commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 645a9e9
Written-by: Reviewer
Attestation: 645a9e9 role=Reviewer

Ran at this tip:

$ cd core && DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness TZ=UTC node --import ./test/harness-resolve.mjs --test test/agents.test.js
# tests 16  # pass 16  # fail 0

$ node getblob.mjs core/src/host/agents.js bfc62959e68bc685f0730704b466a5f9ba276509 agents.base.js   # base blob 6b569c3c
$ cp agents.base.js tip/core/src/host/agents.js && cd tip/core && DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness TZ=UTC node --import ./test/harness-resolve.mjs --test test/agents.test.js
# tests 16  # pass 14  # fail 2   (not ok 9, not ok 10 — the two new assertions)

$ cp /data/dsh/bot/workspace/r2617/agents.tip.js src/host/agents.js && DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness TZ=UTC node --import ./test/harness-resolve.mjs --test test/agents.test.js
# tests 16  # pass 16  # fail 0

$ node scripts/ds-bot-patches.mjs check
ok 10 patches apply cleanly in order; ok core/ equals ds-bot/ + patches/ds-bot/  (exit 0)

$ cd core && /data/dsh/bot/workspace/d2607/ox/node_modules/.bin/oxlint src test
Found 81 warnings and 0 errors.  (exit 0)

$ node .github/scripts/changelog.mjs check
changelog: 18 fragment(s) in changelog.d/ are well formed

$ cd core && DSH_HARNESS=/data/dsh/bot/workspace/d2607/repo/core/dev/harness TZ=UTC node --import ./test/harness-resolve.mjs /data/dsh/bot/workspace/r2617/verify.mjs
A on-disk sessions: ["s2","s3"] archived: ["s1"]
B first result: {"ok":false,"error":{"code":"bot/refused","message":"a Session was added while the Agent was being removed, so the Agent stays; remove it again"}} archived: ["s1","s2"]
B retry result: ok, agents {}, archived ["s1","s2","s3"]
BOTH BRANCHES OK

Not run: full npm run verify (this box runs other lines), smoke bench, build-client --check (core/client.js and src/client/ are not in this diff).

Scope and review:

  • Changed files are exactly the five the body lists. git diff of the two agents.js blobs is one hunk (@@ -185,12 +185,27 @@), inside removeAgent only: archiveAgentSession, createAgentSession, adoptAgentSession, addAgent's rollback and rt.mutate are byte-identical to base. No core/client.js, no ruleset, no CI, no other subsystem; docs page updated and one changelog fragment added (host: remove-agent writes back the Session list it read before awaiting the archives, dropping a Session added meanwhile #2616).
  • Kept branch (a): archived = sessions.filter(id => !kept.includes(id)) and rt.mutate filters the live record by that set, never writing the snapshot back. Independently reproduced (not only via the PR test): s2's archive fails, s1's archive held in flight, s3 added meanwhile → state.json on disk holds ["s2","s3"], the removal throws the original session is running, archived == ["s1"].
  • All-archived branch (b): late is computed and the record rewritten inside rt.mutate, delete state.agents[agentId] only when late is empty, and the retryable throw is outside the change. Independently reproduced: both archives succeed, last one held in flight, s3 added → record persists with ["s3"] and the retryable refusal is returned; an immediate second remove-agent archives s3 and deletes the record, leaving archived == ["s1","s2","s3"].
  • Patch carrier: scripts/ds-bot-patches.mjs check is green, and patches/ds-bot/0001-core-fixes.patch carries the same hunk; patches/ds-bot/files/ holds no mirror of src/host/agents.js on main, so the file set is right.
  • Red first: base agents.js (blob 6b569c3c, sha matches the PR diff index) turns exactly tests 9 and 10 red with the stated symptoms; tip blob 5fb864b7 is 16/16 green.
  • Checks at the tip: tests-ok success; merge-gate, risk tier, reviewed tip, agent-audience, package, plugins, Node 24, mock E2E success; skipped/cancelled entries are the duplicate matrix rows. enqueue-guard fails only with no Verifier report names the tip 645a9e95cec3 — the missing PASS this comment supplies.
  • Body: Fixes #2616, Owner: Dev, Reviewer: Reviewer (not the Owner), label agent-pr, checkpoint block 1213 chars (summary 469, 5 files, checks at this tip). No hold, no comment asking not to merge.

@github-actions github-actions Bot added the pass label Nov 7, 2026
@Birfy
Birfy added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit f833b1c Nov 7, 2026
17 of 19 checks passed
@Birfy
Birfy deleted the dev/2616-remove-agent-live-sessions branch November 7, 2026 15:29
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

host: remove-agent writes back the Session list it read before awaiting the archives, dropping a Session added meanwhile

1 participant